package uk.ac.lkl.lpp.model.xml;



import java.util.Map;


import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import uk.ac.lkl.common.util.ds.AbstractNotifyingList;
import uk.ac.lkl.common.util.ds.NotifyingList;
import uk.ac.lkl.common.util.ds.NotifyingMap;

import uk.ac.lkl.lpp.model.PedagogyPlanModel;
import uk.ac.lkl.lpp.model.ldo.TeachingMethod;
import uk.ac.lkl.lpp.ui.BackCompat;



public class MapProcessor extends ModelElementProcessor {

    public MapProcessor() {
        super("Map");
    }


    public void convertDataToElements(PedagogyPlanModel plan,
                                      Document document,
                                      Element pedagogyPlanElement) {

        Element hoursElement = document.createElement("TeachingMethodHoursAllocationSet");
        pedagogyPlanElement.appendChild(hoursElement);

        // hack to use this to look up indices all the time
        AbstractNotifyingList<TeachingMethod> teachingMethods = plan.getList("main", TeachingMethod.class);

        Map<TeachingMethod, Float> map = plan.getMap("TeachingMethodHoursAllocation",
                                                     TeachingMethod.class,
                                                     Float.class);
        for (Map.Entry<TeachingMethod, Float> entry : map.entrySet()) {
            TeachingMethod teachingMethod = entry.getKey();
            Float hours = entry.getValue();

            // user didn't specify it
            if (hours == null)
                continue;

            int index = teachingMethods.indexOf(teachingMethod);

            Element entryElement = document.createElement("TeachingMethodHoursAllocation");
            entryElement.setAttribute("teachingMethodIndex",
                                      Integer.toString(index));
            entryElement.setAttribute("hours", Float.toString(hours));

            hoursElement.appendChild(entryElement);
        }
    }


    /**
     * Process each map element in turn and create the appropriate map
     * in memory.
     * 
     * If indices used in map keys then assumes is a list previously
     * defined.
     * 
     */
    public void convertElementToData(PedagogyPlanModel plan, Element element) {
        try {
            String sourceClassName = element.getAttribute("sourceClass");

            // hack to convert pre 0.72 data files
            if (BackCompat.isOldForm(sourceClassName)) sourceClassName = BackCompat.upgrade(sourceClassName);

            Class sourceClass = Class.forName(sourceClassName);

            NotifyingMap map = new NotifyingMap();
            
            AbstractNotifyingList<TeachingMethod> teachingMethods = plan.getList("main", TeachingMethod.class);

            NodeList nodes = element.getElementsByTagName("TeachingMethodHoursAllocation");
            for (int i = 0; i < nodes.getLength(); i++) {
                try {
                    Element childElement = (Element) nodes.item(i);

                    String indexString = childElement.getAttribute("teachingMethodIndex");
                    int index = Integer.parseInt(indexString);
                    TeachingMethod teachingMethod = teachingMethods.get(index);

                    String hoursString = childElement.getAttribute("hours");
                    float hours = Float.parseFloat(hoursString);

                    map.put(teachingMethod, hours);
                }
                catch (NumberFormatException e) {
                    // todo: add to warning list
                    e.printStackTrace();
                }
            }
            plan.addMap("TeachingMethodHoursAllocation",
                        TeachingMethod.class,
                        Float.class,
                        map);
        }

        catch (ClassNotFoundException e) {

        }
    }

}
